package com.sxf.auth.login.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.sxf.auth.enums.SmsTypeEnum;
import com.sxf.auth.login.vo.*;
import com.sxf.cache.CacheUtil;
import com.sxf.cache.EhcacheElementType;
import com.sxf.common.exceptions.BusinessException;
import com.sxf.consts.YtConsts;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.Objects;
import java.util.concurrent.ThreadLocalRandom;

/**
 * @author Leo
 */
@Service
public class SmsService {

    private static final Logger logger = LoggerFactory.getLogger(SmsService.class);

	public static final String SEND_CODE_PREFIX = "SEND_CODE:";
	public static final String SEND_CODE_TIMES_PREFIX = "SEND_CODE:TIMES:";
	public static final String SEND_CODE_AVAILABLE_TIMES_PREFIX = "SEND_CODE:AVAILABLE:TIMES:";
	public static final String SEND_CODE_VALIDATE_PREFIX = "SEND_CODE:VALIDATE:";
	public static final String DEFAULT_MOBILE="13500010001";
	public static final String DEFAULT_MOBILE_SMS_CODE="999999";
	/**
	 * 验证码有效次数
	 */
	@Value("${sms.validateTimes:2}")
	private Long smsValidateTimes;

	@Value("${sms.smsAppName:}")
    private String smsAppName;
	
	@Value("${sms.smsTemplateName:}")
    private String smsTemplateName;

	@Autowired
	UserService userService;

	@Autowired
	CacheUtil cacheUtil;

	@Autowired
	AliYunSmsTool sendSms;

	/**
	 * todo 修改返回值
	 * @param sendCodeDTO
	 * @return
	 */
	public SendSmsCodeRes sendCode(SendSmsCodeReq sendCodeDTO) {
		SendSmsCodeRes res = new SendSmsCodeRes();
		SmsTypeEnum smsType = SmsTypeEnum.getEnumByCode(sendCodeDTO.getSmsType());
		String phoneNo = sendCodeDTO.getUserMobile();

		Object validateValue = cacheUtil.get(EhcacheElementType.SMSCODE,SEND_CODE_TIMES_PREFIX + smsType.getCode() + ":" + phoneNo);
		if(!Objects.isNull(validateValue)) {
//			Long timeout = redisClient.getExpire(SEND_CODE_TIMES_PREFIX + smsType.getCode() + ":" + phoneNo);
			//todo 时间简单处理，后面有时间再优化
			throw new BusinessException("该手机号已经发送了验证码，请于稍后重试");
		}

		//协调员忘记密码，校验手机号是否存在
		if(SmsTypeEnum.FORGET_PASSWORD.getCode().equals(sendCodeDTO.getSmsType())){
			if(!userService.isCoorExist(sendCodeDTO.getUserMobile())){
				throw new BusinessException("该手机号不存在！");
			}
		}

		//校验手机号是否注册
		ValidUserMobileReq param = new ValidUserMobileReq();
		param.setUserMobile(sendCodeDTO.getUserMobile());
		ValidUserMobileRes validUserMobileRes = userService.validUserMobile(param);
		if(validUserMobileRes.getExist()){
			res.setMobileExist(YtConsts.Y);
		}else{
			res.setMobileExist(YtConsts.N);
		}

		String code = generateCode();
		res.setSendCode(code);
		SmsVo smsVo = new SmsVo();
		smsVo.setMobile(sendCodeDTO.getUserMobile());
		smsVo.setSmsCode(code);
		if(SmsTypeEnum.SENDCODE_LOGIN.getCode().equals(sendCodeDTO.getSmsType())){
			smsVo.setTemplateId("SMS_317160006");
		}else if(SmsTypeEnum.FORGET_PASSWORD.getCode().equals(sendCodeDTO.getSmsType())){
			smsVo.setTemplateId("SMS_317160006");
		}
		try {
			sendSms.sendSms(smsVo);
		} catch (Exception e) {
			logger.error("短信返送异常-{}",e.getMessage());
			throw new BusinessException("短信发送失败");
		}

		String key = SEND_CODE_PREFIX + smsType.getCode() + ":" + phoneNo;
		cacheUtil.set(EhcacheElementType.SMSCODE,key,code);
		logger.error("get value-{}",cacheUtil.get(EhcacheElementType.SMSCODE,key));
		cacheUtil.set(EhcacheElementType.SMSCODE,SEND_CODE_TIMES_PREFIX + smsType.getCode() + ":" + phoneNo, code);
		cacheUtil.set(EhcacheElementType.SMSCODE,SEND_CODE_AVAILABLE_TIMES_PREFIX + smsType.getCode() + ":" + phoneNo, 1);

		return res;
	}
	
	public Boolean validate(ValidateSmsCodeReq validateSmsCodeDTO) {
		logger.info("valid smsCode start ----{}",validateSmsCodeDTO.getCode());
		SmsTypeEnum smsType = SmsTypeEnum.getEnumByCode(validateSmsCodeDTO.getSmsType());
		String code = validateSmsCodeDTO.getCode();
		String phoneNo = validateSmsCodeDTO.getUserMobile();

		if(DEFAULT_MOBILE.equals(phoneNo) && DEFAULT_MOBILE_SMS_CODE.equals(code)){
			//小程序上架审批需要
			return true;
		}

		String key = SEND_CODE_PREFIX + smsType.getCode() + ":" + phoneNo;
		
		Object redisObject = cacheUtil.get(EhcacheElementType.SMSCODE,key);
		
		if(Objects.isNull(redisObject)) {
			throw new BusinessException("验证码已失效，请重新发送");
		}
		
		String redisCode = (String) redisObject;
		if(!redisCode.equals(code)) {
			Object availableTimes = cacheUtil.get(EhcacheElementType.SMSCODE,SEND_CODE_AVAILABLE_TIMES_PREFIX + smsType.getCode() + ":" + phoneNo);
			if(!Objects.isNull(availableTimes) && Long.parseLong(String.valueOf(availableTimes)) < smsValidateTimes ) {
				cacheUtil.set(EhcacheElementType.SMSCODE,SEND_CODE_AVAILABLE_TIMES_PREFIX + smsType.getCode() + ":" + phoneNo,
						Long.parseLong(String.valueOf(availableTimes)) + 1);
			} else {
				deleteAll(key, smsType, phoneNo);
			}
			throw new BusinessException("验证码错误");
		}
		deleteAll(key, smsType, phoneNo);
		cacheUtil.delete(EhcacheElementType.SMSCODE,SEND_CODE_TIMES_PREFIX + smsType.getCode() + ":" + phoneNo);
// 		String uuid = UUID.randomUUID().toString().replaceAll("-", "");
//		CacheUtil.set(EhcacheElementType.CAPTCHA,SEND_CODE_VALIDATE_PREFIX + smsType.getCode() + ":" + phoneNo, uuid);
//
//		Map<String, String> result = new HashMap<String, String>();
//		result.put("uuid", uuid);
		logger.info("valid smsCode end ----{}",validateSmsCodeDTO.getCode());
		return true;
	}

	public void validateUuid(SmsTypeEnum smsType, String phoneNo, String uuid) {
		Object uuidObject = cacheUtil.get(EhcacheElementType.SMSCODE,SEND_CODE_VALIDATE_PREFIX + smsType.getCode() + ":" + phoneNo);
		if(Objects.isNull(uuidObject)) {
			throw new BusinessException("操作超时,请重新认证");
		}

		String uuidCode = (String) uuidObject;
		if(!uuidCode.equals(uuid)) {
			throw new BusinessException("短信认证失败");
		}
		cacheUtil.delete(EhcacheElementType.SMSCODE,SEND_CODE_VALIDATE_PREFIX + smsType.getCode() + ":" + phoneNo);
	}

	
	private void deleteAll(String key, SmsTypeEnum smsType, String phoneNo) {
		cacheUtil.delete(EhcacheElementType.SMSCODE,key);
		cacheUtil.delete(EhcacheElementType.SMSCODE,SEND_CODE_AVAILABLE_TIMES_PREFIX + smsType.getCode() + ":" + phoneNo);
	}
	
	private String generateCode() {
		return String.valueOf(ThreadLocalRandom.current().nextInt(100000, 999999));
	}

}
